import relationalStore from '@ohos.data.relationalStore'
import { DaoConfig } from '../db/DaoConfig'
import { SqlInfoBuilder} from '../db/sqlite/SqlInfoBuilder'
import { DaoType } from '../db/DaoType'
import { QueryCallBack} from '../db/QueryCallBack'
import { DbUpgradeListener} from '../db/DbUpgradeListener'
import { Selector } from '../db/sqlite/Selector'
import SPLogger from './SPLogger'

export class DbUtils {
    private daoMap: Map<string, any>
    private daoConfig: DaoConfig
    private debug = false
    private allowTransaction = false
    private queryCallBack: QueryCallBack

    constructor(daoConfig: DaoConfig)
    constructor(dbDir: string, dbName: string, tableName:string, dbVersion:  number,dbUpgradeListener: DbUpgradeListener )
    constructor(dbConfigOrDir?, dbName?, tableName?, dbVersion?, dbUpgradeListener?) {
        if (!!dbName) {
            this.daoConfig = new DaoConfig()
            this.daoConfig.setDbDir(dbConfigOrDir)
            this.daoConfig.setDbName(dbName)
            this.daoConfig.setTableName(tableName)
            this.daoConfig.setDbVersion(dbVersion)
            this.daoConfig.setDbUpgradeListener(dbUpgradeListener)
        } else {
            this.daoConfig = dbConfigOrDir
        }
        this.createStore()
    }
    public setCallback(callBack: QueryCallBack) {
        this.queryCallBack = callBack
    }
    public configDebug(debug: boolean): DbUtils {
        this.debug = debug
        return this
    }
    public createStore() {
        this.execNonQuery('', null, DaoType.CREATE_STORE)
    }

    public createTableIfNotExist() {
        var sqlInfo = SqlInfoBuilder.buildCreateTableSqlInfo(this)
        this.execNonQuery(sqlInfo, null, DaoType.CREATE_TABLE)
    }

    public save(valueBuckets) {
        this.execNonQuery(valueBuckets, null, DaoType.INSERT)
    }

    public saveAll(valueBuckets) {
        for (let i = 0; i < valueBuckets.length; i++) {
            this.execNonQuery(valueBuckets[i], null, DaoType.INSERT)
        }
    }
    public findFirst(selector: Selector) {
        this.execNonQuery("", selector, DaoType.QUERY_FIRST)
    }
    public update(valuesBucket: any, selector: Selector) {
        this.execNonQuery(valuesBucket, selector, DaoType.UPDATE)
    }
    public delete(selector: Selector) {
        this.execNonQuery("", selector, DaoType.DELETE)
    }
    public dropTable(tableName: string) {
        if(this.daoConfig == null || this.daoConfig.getTableName() == null) return
        this.execNonQuery("DROPTABLE" + tableName, null, DaoType.DROPTABLE)
    }

    /*
     * 删除数据库
     */
    public dropDb() {
        if (this.daoConfig.getDbName() == null) return
        relationalStore.deleteRdbStore(globalThis.abilityContext, this.daoConfig.getDbName())
            .then(() => {
                this.daoConfig.setDbName(null)
            })
    }

    public execCreate(tableMap: Map <string, string>) {
        if (this.daoConfig == null) return;
        const STORE_CONFIG: relationalStore.StoreConfig = {
            name: this.daoConfig.getDbName(),
            securityLevel: relationalStore.SecurityLevel.S1
        }
         relationalStore.getRdbStore(globalThis.abilityContext, STORE_CONFIG).then(rdbStore => {
            tableMap.forEach((value, key) => {
                 rdbStore.executeSql(value, null, function(e) {
                    if (e) {
                        SPLogger.ERROR('DbUtils','create table failed：' + value + ', error: ' + e.message)
                    }else {
                        SPLogger.INFO('DbUtils','create table successfully：' + value)
                    }
                })
            })
        })
    }
    public execNonQuery<T>(sql:any, selector: Selector, type: string): Array<T> {
        if (this.daoConfig == null) return;
        var tableName = this.daoConfig.getTableName()
        const STORE_CONFIG:relationalStore.StoreConfig = {
            name: this.daoConfig.getDbName(),
            securityLevel: relationalStore.SecurityLevel.S1
        }
        relationalStore.getRdbStore(globalThis.abilityContext, STORE_CONFIG).then(rdbStore => {
            switch (type) {
                case DaoType.CREATE_STORE:
                    break;
                case DaoType.CREATE_TABLE:
                    rdbStore.executeSql(sql, null, function(e) {

                    })
                    break;
                case DaoType.INSERT:
                    let promise = rdbStore.insert(tableName, sql)
                    promise.then(async (ret) => {
                        SPLogger.DEBUG("DbUtils:", tableName + " insert success:" + ret)
                    }).catch(err=>{
                        SPLogger.ERROR("DbUtils:", tableName + " insert err:" + JSON.stringify(err))
                    })
                    break
                case DaoType.QUERY:
                    rdbStore.query(selector == null ? new relationalStore.RdbPredicates(tableName) : selector.predicates, selector.getQueryColumns())
                        .then((resultSet) => {
                            if (resultSet.rowCount < 0) return
                            resultSet.close()
                            resultSet = null
                        })
                    break;
                case DaoType.QUERY_FIRST:
                    rdbStore.query(selector.predicates, selector.getQueryColumns())
                        .then((resultSet) => {
                            if (resultSet.rowCount < 0) return;
                            var resultMap = new Map()
                            for(var i = 0; i < 1; i++) {
                                resultSet.goToNextRow()
                                for(var j = 0; j < selector.getQueryColumns().length; j++) {
                                    const name = resultSet.getString(resultSet.getColumnIndex(selector.getQueryColumns()[j]))
                                    resultMap.set(selector.getQueryColumns()[j], name)
                                }
                            }
                            resultSet.close()
                            resultSet = null
                        })
                    break;
                case DaoType.UPDATE:
                    rdbStore.update(sql, selector.predicates)
                        .then(async (ret) => {
                        }).catch(err=> {
                    })
                    break;
                case DaoType.DELETE:
                    rdbStore.delete(selector.predicates)
                        .then((rows)=>{
                        })
                    break;
                case DaoType.DROPTABLE:
                    rdbStore.executeSql(sql, null)
                    break;
            }
        }).catch(e=>{
            SPLogger.ERROR('DbUtils','get rdb failed：' + e.message)
        })
        relationalStore.getRdbStore(globalThis.abilityContext, STORE_CONFIG, function(err, rdbStore) {
            if (err) {
                return
            }
        })
    }
    public getDaoConfig(): DaoConfig {
        return this.daoConfig
    }
}
